/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.modules.nashorn.execution.options;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import java.util.prefs.Preferences;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.platform.PlatformsCustomizer;
import org.netbeans.modules.java.api.common.ui.PlatformUiSupport;
import org.netbeans.modules.nashorn.execution.NashornPlatform;
import org.netbeans.modules.options.java.api.JavaOptions;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle;

/**
 *
 * @author Martin Entlicher
 */
@OptionsPanelController.Keywords(keywords={"JavaScript, Nashorn", "#KW_JavaScript"}, location=JavaOptions.JAVA, tabTitle= "#LBL_JSonJVM")
public class JavaScriptNashornPanel extends javax.swing.JPanel {

    private final JavaScriptNashornOptionsPanelController optionsController;
    private final String nashorn;
    private final String graalJs;

    /**
     * Creates new form JavaScriptNashornPanel
     */
    public JavaScriptNashornPanel(JavaScriptNashornOptionsPanelController optionsController) {
        this.nashorn = NbBundle.getMessage(JavaScriptNashornPanel.class, "LBL_Nashorn");
        this.graalJs = NbBundle.getMessage(JavaScriptNashornPanel.class, "LBL_GraalJs");
        this.optionsController = optionsController;
        initComponents();
        platformsComboBox.setModel(new NashornPlatformComboBoxModel());
        platformsComboBox.addActionListener(new PlatformChangeListener(true));
        engineSelector.addActionListener(new PlatformChangeListener(false));
        setFieldsEnabled();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        infoLabel = new javax.swing.JLabel();
        platformsLabel = new javax.swing.JLabel();
        platformsComboBox = new javax.swing.JComboBox();
        engineOptionsLabel = new javax.swing.JLabel();
        engineOptionsTextField = new javax.swing.JTextField();
        platformHintLabel = new javax.swing.JLabel();
        argumentsLabel = new javax.swing.JLabel();
        argumentsTextField = new javax.swing.JTextField();
        platformManageButton = new javax.swing.JButton();
        fillPanel = new javax.swing.JPanel();
        engineLabel = new javax.swing.JLabel();
        engineSelector = new javax.swing.JComboBox<>();

        setLayout(new java.awt.GridBagLayout());

        org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.infoLabel.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        add(infoLabel, gridBagConstraints);

        platformsLabel.setLabelFor(platformsComboBox);
        org.openide.awt.Mnemonics.setLocalizedText(platformsLabel, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.platformsLabel.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(17, 0, 0, 0);
        add(platformsLabel, gridBagConstraints);

        platformsComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                platformsComboBoxActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 284;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(12, 24, 0, 0);
        add(platformsComboBox, gridBagConstraints);

        engineOptionsLabel.setLabelFor(engineOptionsTextField);
        org.openide.awt.Mnemonics.setLocalizedText(engineOptionsLabel, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.engineOptionsLabel.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 6;
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(14, 0, 0, 0);
        add(engineOptionsLabel, gridBagConstraints);

        engineOptionsTextField.setText(org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.engineOptionsTextField.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 6;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 312;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(12, 24, 0, 0);
        add(engineOptionsTextField, gridBagConstraints);

        platformHintLabel.setFont(platformHintLabel.getFont().deriveFont(platformHintLabel.getFont().getSize()-1f));
        org.openide.awt.Mnemonics.setLocalizedText(platformHintLabel, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.platformHintLabel.text")); // NOI18N
        platformHintLabel.setEnabled(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 5;
        gridBagConstraints.gridwidth = 6;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 329;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(6, 24, 0, 0);
        add(platformHintLabel, gridBagConstraints);

        argumentsLabel.setLabelFor(argumentsTextField);
        org.openide.awt.Mnemonics.setLocalizedText(argumentsLabel, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.argumentsLabel.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 8;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0);
        add(argumentsLabel, gridBagConstraints);

        argumentsTextField.setText(org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.argumentsTextField.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 8;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 312;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(6, 24, 172, 0);
        add(argumentsTextField, gridBagConstraints);

        org.openide.awt.Mnemonics.setLocalizedText(platformManageButton, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.platformManageButton.text")); // NOI18N
        platformManageButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                platformManageButtonActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 8;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridheight = 4;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 0);
        add(platformManageButton, gridBagConstraints);

        fillPanel.setMinimumSize(new java.awt.Dimension(0, 0));
        fillPanel.setLayout(null);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 9;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        gridBagConstraints.weightx = 0.1;
        gridBagConstraints.weighty = 0.1;
        add(fillPanel, gridBagConstraints);

        engineLabel.setLabelFor(engineSelector);
        org.openide.awt.Mnemonics.setLocalizedText(engineLabel, org.openide.util.NbBundle.getMessage(JavaScriptNashornPanel.class, "JavaScriptNashornPanel.engineLabel.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHWEST;
        add(engineLabel, gridBagConstraints);

        engineSelector.setModel(initEngineSelector());
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(12, 24, 0, 0);
        add(engineSelector, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents

    ComboBoxModel<String> initEngineSelector() {
        Vector<String> names = new Vector<>();
        JavaPlatform p = getSelectedPlatform();
        if (NashornPlatform.isNashornSupported(p)) {
            names.add(nashorn);
        }
        if (NashornPlatform.isGraalJsSupported(p)) {
            if (NashornPlatform.isGraalJSPreferred(p)) {
                names.add(0, graalJs);
            } else {
                names.add(graalJs);
            }
        }
        return new DefaultComboBoxModel<>(names);
    }

    private void platformManageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_platformManageButtonActionPerformed
        PlatformsCustomizer.showCustomizer(null);
    }//GEN-LAST:event_platformManageButtonActionPerformed

    private void platformsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_platformsComboBoxActionPerformed
        setFieldsEnabled();
    }//GEN-LAST:event_platformsComboBoxActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel argumentsLabel;
    private javax.swing.JTextField argumentsTextField;
    private javax.swing.JLabel engineLabel;
    private javax.swing.JLabel engineOptionsLabel;
    private javax.swing.JTextField engineOptionsTextField;
    private javax.swing.JComboBox<String> engineSelector;
    private javax.swing.JPanel fillPanel;
    private javax.swing.JLabel infoLabel;
    private javax.swing.JLabel platformHintLabel;
    private javax.swing.JButton platformManageButton;
    private javax.swing.JComboBox platformsComboBox;
    private javax.swing.JLabel platformsLabel;
    // End of variables declaration//GEN-END:variables

    private JavaPlatform getSelectedPlatform() {
        Object selObj = platformsComboBox.getSelectedItem();
        if (selObj == null) {
            return null;
        } else {
            return PlatformUiSupport.getPlatform(selObj);
        }
    }

    private void selectPlatform(JavaPlatform platform) {
        int n = platformsComboBox.getItemCount();
        for (int i = 0; i < n; i++) {
            Object obj = platformsComboBox.getItemAt(i);
            JavaPlatform p = PlatformUiSupport.getPlatform(obj);
            if (platform.equals(p)) {
                platformsComboBox.setSelectedIndex(i);
                return ;
            }
        }
    }

    void load() {
        JavaPlatform njp = NashornPlatform.getDefault().getPlatform();
        if (njp != null) {
            selectPlatform(njp);
        }
        final Preferences p = Settings.getPreferences();
        String options = p.get(Settings.PREF_NASHORN_OPTIONS, null);
        String arguments = p.get(Settings.PREF_NASHORN_ARGUMENTS, null);
        engineOptionsTextField.setText(options != null ? options : "");
        argumentsTextField.setText(arguments != null ? arguments : "");
        if (isSettingsNashorn(njp)) {
            engineSelector.setSelectedItem(nashorn);
        } else {
            engineSelector.setSelectedItem(graalJs);
        }
    }

    private boolean isSettingsNashorn(JavaPlatform njp) {
        final Preferences p = Settings.getPreferences();
        String item = p.get(Settings.PREF_NASHORN, null);
        if (item == null) {
            return !NashornPlatform.isGraalJSPreferred(njp);
        } else {
            return p.getBoolean(Settings.PREF_NASHORN, false);
        }
    }

    void store() {
        NashornPlatform.getDefault().setPlatform(getSelectedPlatform());
        String options = engineOptionsTextField.getText().trim();
        if (options.isEmpty()) {
            Settings.getPreferences().remove(Settings.PREF_NASHORN_OPTIONS);
        } else {
            Settings.getPreferences().put(Settings.PREF_NASHORN_OPTIONS, options);
        }
        String arguments = argumentsTextField.getText().trim();
        if (arguments.isEmpty()) {
            Settings.getPreferences().remove(Settings.PREF_NASHORN_ARGUMENTS);
        } else {
            Settings.getPreferences().put(Settings.PREF_NASHORN_ARGUMENTS, arguments);
        }
        Settings.getPreferences().putBoolean(Settings.PREF_NASHORN, isNashorn());
    }

    private boolean isNashorn() {
        Object item = engineSelector.getSelectedItem();
        return item == nashorn;
    }

    boolean valid() {
        return true;
    }

    boolean isChanged() {
        if (NashornPlatform.getDefault().getPlatform() != getSelectedPlatform()) {
            return true;
        }
        if (!engineOptionsTextField.getText().trim().equals(
                Settings.getPreferences().get(Settings.PREF_NASHORN_OPTIONS, ""))) {
            return true;
        }
        if (!argumentsTextField.getText().trim().equals(
                Settings.getPreferences().get(Settings.PREF_NASHORN_ARGUMENTS, ""))) {
            return true;
        }
        if (isSettingsNashorn(getSelectedPlatform()) != isNashorn()) {
            return true;
        }
        return false;
    }

    private void setFieldsEnabled() {
        boolean enabled = getSelectedPlatform() != null;
        engineOptionsTextField.setEnabled(enabled);
        argumentsTextField.setEnabled(enabled);
    }

    private class PlatformChangeListener implements ActionListener {
        private final boolean resetEngines;

        PlatformChangeListener(boolean resetEngines) {
            this.resetEngines = resetEngines;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            optionsController.changed();
            if (resetEngines) {
                engineSelector.setModel(initEngineSelector());
            }
        }
    }
}
